<?php
namespace Monkey\Database\QueryHelper;

use Monkey\Database\Driver;
use MonkeyException;

/**
 * Sqlite数据库查询助手\Monkey\Database\QueryHelper\Sqlite
 * @package    Monkey\Database\QueryHelper
 * @author     HuangYi
 * @copyright  Copyright (c) 2011-07-01——2013-03-30
 * @license    New BSD License
 * @version    $Id: \Monkey\Database\QueryHelper\Sqlite.php 版本号 2013-03-30 $
 */
class Sqlite implements _Interface
{
    /**
     * 字段类型
     */
    private $fieldType = array(
        'pk'       => 'integer PRIMARY KEY AUTOINCREMENT NOT NULL',
        'string'   => 'varchar(255)',
        'text'     => 'text',
        'integer'  => 'integer',
        'int_not'  => 'integer NOT NULL DEFAULT 0',
        'float'    => 'float',
        'datetime' => 'datetime',
        'time'     => 'time',
        'date'     => 'date',
        'binary'   => 'blob',
        'boolean'  => 'tinyint(1)',
        'bool_not' => 'tinyint(1) NOT NULL DEFAULT 0',
    );
    /**
     * @var \Monkey\Database\Driver\_Interface
     */
    private $driver;
    /**
     * @param \Monkey\Database\Driver\_Interface &$driver
     * @return \Monkey\Database\QueryHelper\_Interface
     */
    public function _reset( Driver\_Interface &$driver){
        $this->driver=$driver;
        return $this;
    }
    /**
     * 转换关键字冲突标记
     * 需要注释的关键词标签内部不应有空格
     * @param string $string 字符串
     * @return string
     */
    public function quoteKeywords(&$string){
        return preg_replace('/\[:(\S+?):\]/','`$1`',$string);
    }
    /**
     * 获取系统内置字段类型
     * @param string $type 类型标识或自定义类型
     * @return string
     */
    public function getFieldType($type){
        if(isset($this->fieldType[$type])) return $this->fieldType[$type];
        return $type;
    }
    /**
     * 对sql参数中的特殊字符进行转义
     * @param string|array $data 待转义的数据
     * @return string|array
     */
    public function escape($data){
        return $this->driver->escape($data);
    }
    /**
     * 直接查询
     * @param string $sql 查询语句
     * @return \Monkey\Database\Driver\_Interface
     */
    public function query($sql){
        if(!$sql)MonkeyException::halt('sql语句为空，无法执行query操作！',1024,__FILE__,__LINE__);
        return $this->driver->query($this->quoteKeywords($sql));
    }
    /**
     * 执行插入操作
     * @param array $options 操作选项，不建议手工构建这个参数，使用插入助手即可
     * @return \Monkey\Database\Driver\_Interface
     */
    public function insert($options){
        $sql=$this->buildInsert($options);
        return $this->query($sql);
    }
    /**
     * 执行更新操作
     * @param array $options 操作选项，不建议手工构建这个参数，使用更新助手即可
     * @return \Monkey\Database\Driver\_Interface
     */
    public function update($options){
        $sql=$this->buildUpdate($options);
        return $this->query($sql);
    }
    /**
     * 执行select操作
     * @param array $options 操作选项，不建议手工构建这个参数，使用select助手即可
     * @return \Monkey\Database\Driver\_Interface
     */
    public function select($options){
        $sql=$this->buildSelect($options);
        return $this->query($sql);
    }
    /**
     * 执行删除操作
     * @param array $options 操作选项，不建议手工构建这个参数，使用删除助手即可
     * @return \Monkey\Database\Driver\_Interface
     */
    public function delete($options){
        $sql=$this->buildDelete($options);
        return $this->query($sql);
    }
    /**
     * 生成SQL插入语句（不要直接用）
     * @param array $options 插入选项，多维数组
     * @return string
     */
    public function buildInsert($options){
        if(!$options['table']) return '';
        if(!$options['values']) return '';
        $options['values']=$this->driver->escape($options['values']);
        if(!$options['fields']) $options['fields']=array_keys($options['values'][0]);
        $_row=array();
        foreach($options['values'] as $key=>$row){
            $_row=array();
            foreach($options['fields'] as $field) $_row[$field]=$row[$field];//修正字段顺序
            $options['values'][$key]='('.implode(', ',$_row).')';//连接数据行
        }
        $insert= 'INSERT';
        $options['values']=implode(', ',$options['values']);
        return $insert.' INTO  [:{:'.$options['table'].':}:] ([:'.implode(':], [:',$options['fields']).':]) VALUES '.$options['values'];
    }
    /**
     * 生成SQL更新语句（不要直接用）
     * @param array $options 插入选项，多维数组
     * @return string
     */
    public function buildUpdate($options){
        if(!$options['table'])return '';
        if(!$options['values'])return '';
        $options['values']=$this->driver->escape($options['values']);
        $values=array();
        foreach($values as $field=>$value){
            $values[$field]='[:'.$field.':]='.$value;
        }
        $values=implode(', ', $values);
        $where=isset($options['where'])?' WHERE '.implode(' ',$options['where']).' ':'';
        $orderby=$this->_by($options['orderby'],' ORDER BY ');
        $limit=isset($options['limit'])?' LIMIT '.$options['limit']['start'].','.$options['limit']['length']:'';
        return 'UPDATE [:{:'.$options['table'].':}:] SET '.$values.$where.$orderby.$limit;
    }
    /**
     * 生成Select查询语句（不要直接用）
     * @param array $options 插入选项，多维数组
     * @return string
     */
    public function buildSelect($options){
        if(!$options['table'] && !$options['join'])return '';
        $select='';
        isset($options['into']) and $select='CREATE TABLE '.$options['into'].' AS ';
        $select.= $options['distinct']?'SELECT DISTINCT':'SELECT';
        $select.=' '.(isset($options['fields'])? implode(', ', $options['fields'] ) : '*');
        $select.=' FROM';
        isset($options['table']) and $select.=' '.implode(', ', $options['table'] );
        isset($options['join']) and $select.=' '.implode(', ',$options['join']);
        isset($options['where']) and $select.=' WHERE '.implode(' ',$options['where']);
        $select.=$this->_by($options['groupby'],' GROUP BY ');
        isset($options['having']) and $select.=' HAVING '.implode(' ',$options['having']);
        $select.=$this->_by($options['orderby'],' ORDER BY ');
        isset($options['limit']) and $select.=' LIMIT '.$options['limit']['start'].','.$options['limit']['length'];
        return $select;
    }
    /**
     * 生成SQL删除语句（不要直接用）
     * @param array $options 插入选项，多维数组
     * @return string
     */
    public function buildDelete($options){
        if(!$options['table']) return '';
        $where=isset($options['where'])?' WHERE '.implode(' ',$options['where']).' ':'';
        $orderby=$this->_by($options['orderby'],' ORDER BY ');
        $limit=isset($options['limit'])?' LIMIT '.$options['limit']['start'].','.$options['limit']['length']:'';
        return 'DELETE FROM [:{:'.$options['table'].':}:] '.$where.$orderby.$limit;
    }
    private function _by($by,$type=''){
        if(!$by)return '';
        foreach($by as $key=>$fields){
            $by[$key]=implode(', ',$fields).' '.$key.' ';
        }
        return $type.implode(', ',$by).' ';
    }
    /**
     * 生成创建数据表的SQL语句
     * @param string $tableName 表名称
     * @param array  $fields   表字段
     * @param null|string $options   表扩展设置
     * @return boolean
     */
    public function createTable($tableName,$fields,$options=null){
        $cols=array();
        foreach ($fields as $field => $type) {
            $cols[] = '\t [:'.$field.':] '.$this->getFieldType($type);
        }
        $sql= 'CREATE TABLE [:{:'.$tableName.':}:] (\n'.implode(',\n',$cols).'\n) '. $options;
        return $this->driver->query($this->quoteKeywords($sql))->isSuccess();
    }
    /**
     * 删除数据表
     * @param string $tableName 表名称
     * @return boolean
     */
    public function dropTable($tableName){
        is_array($tableName) and $tableName=implode(':}:], [:{:',$tableName);
        $sql= 'DROP TABLE IF EXISTS [:{:'.$tableName.':}:]';
        return $this->driver->query($this->quoteKeywords($sql))->isSuccess();
    }
    /**
     * 重命名表
     * @param string $tableName    表名称
     * @param string $newTableName 表新名称
     * @return boolean
     */
    public function renameTable($tableName, $newTableName){
        $sql= 'ALTER TABLE [:{:'.$tableName.':}:] RENAME TO [:{:'.$newTableName.':}:]';
        return $this->driver->query($this->quoteKeywords($sql))->isSuccess();
    }
    /**
     * 清空数据表
     * @param string $tableName 表名称
     * @return boolean
     */
    public function truncateTable($tableName){
        $sql='DELETE FROM [:{:'.$tableName.':}:]';
        $this->driver->query($this->quoteKeywords($sql));
        if(!$this->driver->isSuccess())return false;
        $result=$this->driver->query('SELECT * FROM `sqlite_sequence`')->resultAll(FETCH_ASSOC);
        $preFix=$this->driver->getPreFix();
        foreach($result as $val){
            if($val['name']==($preFix.$tableName)){
                $sql='CREATE TABLE sqlite_sequence() SET seq=0 WHERE name=[:{:'.$tableName.':}:]';
                $this->driver->query($this->quoteKeywords($sql));
            }
        }
        return true;
    }
    /**
     * 增加字段
     * @param string $tableName 表名称
     * @param string $fieldName 新增的字段名称
     * @param string $fieldType 字段数据类型，可以使用内置， 也可以自定义
     * @return boolean
     */
    public function addField($tableName, $fieldName, $fieldType){
        $sql='ALTER TABLE [:{:'.$tableName.':}:] ADD [:'.$fieldName.':] '.$this->getFieldType($fieldType);
        return $this->driver->query($this->quoteKeywords($sql))->isSuccess();
    }
    /**
     * 删除字段
     * @param string $tableName 表名称
     * @param string $fieldName 字段名称
     * @return boolean
     */
    public function dropField($tableName, $fieldName){
        return false;//MonkeyException::halt('SQLite数据库系统不允许删除表字段',1024,__FILE__,__LINE__);
    }
    /**
     * 重命名字段
     * @param string $tableName 表名称
     * @param string $fieldName      老字段名称
     * @param string $newFieldName 	新字段名称
     * @return boolean
     */
    public function renameField($tableName, $fieldName, $newFieldName){
        return false;//MonkeyException::halt('SQLite数据库系统不允许重命名表字段',1024,__FILE__,__LINE__);
    }
    /**
     * 修改字段属性
     * @param string $tableName 表名称
     * @param string $fieldName      字段名称
     * @param string $fieldType   	字段类型
     * @return boolean
     */
    public function alertField($tableName, $fieldName,$fieldType){
        return false;//MonkeyException::halt('SQLite数据库系统不允许更改表字段',1024,__FILE__,__LINE__);
    }
    /**
     * 读取表字段信息
     * @param string $tableName 表名
     * @return boolean|array
     * 返回结果结构如下：
     * array(
     *      'pri_name'      =>string,
     *      'pri_is_auto'   =>boolean,
     *      'fields_default'=>array,
     *      'fields_type'   =>array,
     * );
     */
    public function getTableMate($tableName){
        $sql='PRAGMA table_info([:{:'.$tableName.':}:])';
        if(!$this->driver->query($this->quoteKeywords($sql))->isSuccess()) return FALSE;
        $tableMate=$this->driver->resultAll();
        $mate['pri_name']=null;
        $mate['pri_is_auto']=false;
        foreach($tableMate as $field){
            $mate['fields_default'][$field['name']]=$field['dflt_value'];
            $mate['fields_type'][$field['name']]=$field['type'];
            if($field['pk']){
                $mate['pri_name']=$field['name'];
                $mate['pri_is_auto']=true;
            }
        }
        return $mate;
    }

}